package connect

import (
	"gim/db"
	"gim/storage"
	"gim/mq"
	"gim/comm"
	"time"
	"sync"
	"net"
	"fmt"
	"encoding/gob"
	log "github.com/golang/glog"
)

var (
	manager *db.Manager
	storage_pool *storage.StorageConnPool
	rmq *mq.RedisMQ
	csrv *ConnectServer
)

type ConnectServer struct {
	host string
	clientSets map[int64](*ClientSet)
	mutex sync.Mutex
}

//接收连接
func (csrv *ConnectServer) Listen() {
	listener, err := net.Listen("tcp", csrv.host)
	if err != nil {
		log.Error("connect server listen err", err)
		return
	}

	go func() {
		for {
			conn, err := listener.Accept()

			if err != nil {
				log.Error("connect server accept err", err)
				return
			}

			client := NewClient(conn)
			client.Run()
		}
	}()
}

func (csrv *ConnectServer) HandleMsg() {
	key := fmt.Sprintf("GIM_MS_S_%s", csrv.host)
	
	go func() {
		for {
			m := rmq.BDequeue(key)
			if m == nil {
				continue
			}
			
			switch m.Cmd {
				case comm.MSG_IM:
					body := m.Body.(*comm.IMMessage)
					csrv.sendMsg(body.Receiver, m)
				case comm.MSG_GROUP_IM:
					body := m.Body.(*comm.IMMessage)
					csrv.sendMsg(body.Receiver, m)
				case comm.MSG_DEVICE_KICK:
					body := m.Body.(*comm.DeviceKick)
					if cs, ok := csrv.clientSets[body.Uid]; ok {
						for device_id, client := range cs.clients {
							if device_id == body.Device_id {
								continue
							}
							
							client.wt <- m
							client.HandleRemoveClient()
						}
					}
				case comm.MSG_INPUTING:
					body := m.Body.(*comm.MessageInputing)
					csrv.sendMsg(body.Receiver, m)
				default:
			}
		}			
	}()
}

func (csrv *ConnectServer) sendMsg(receiver int64, m *comm.Message) {
	//获取目标client
	if cs, ok := csrv.clientSets[receiver]; ok {
		for _, client := range cs.clients {
			client.wt <- m
		}
	}
}

func (csrv *ConnectServer) RegisterClient(client *Client) {
	csrv.mutex.Lock()
	defer csrv.mutex.Unlock()
	
	if cs, ok := csrv.clientSets[client.uid]; ok {
		cs.Add(client)
	} else {
		cs = NewClientSet()
		cs.Add(client)
		csrv.clientSets[client.uid] = cs
	}
}

func (csrv *ConnectServer) RemoveClient(client *Client) {
	csrv.mutex.Lock()
	defer csrv.mutex.Unlock()
	
	if cs, ok := csrv.clientSets[client.uid]; ok {
		cs.Remove(client)
	}
}

func StartConnect(sh string, dbh string, dbp string, mqh string, mqp string, s string) *ConnectServer {
	comm.InitMessage()
	
	//创建storage连接池
	f := storage.DialStorageFun(sh)
	storage_pool = storage.NewStorageConnPool(100, 500, 600 * time.Second, f)
	
	//创建db连接池
	manager = db.NewManager(dbh, dbp)
	
	//创建redis连接池
	rmq = mq.NewRedisMQ(mqh, mqp)
	
	gob.Register(comm.IMMessage{})
	
	csrv = &ConnectServer{
		host : s,
		clientSets : make(map[int64](*ClientSet)),
	}
	
	csrv.HandleMsg()
	
	csrv.Listen()
	
	return csrv
}

func StopConnect(csrv *ConnectServer) {
	mq.StopRedisMQ(rmq)
	db.StopManager(manager)
}